﻿using System;
using TechTalk.SpecFlow;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Xml.Linq;
using System.Collections.Generic;
using Crap4Net.CoverageParsers;
using System.IO;
using Crap4Net.CCParsers;
using System.Reflection;
using System.Linq;

namespace Crap4Net.Specs
{
    [Binding]
    public class Actions
    {
        string _path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        string _ccFileName;
        string _covFileName;

        private XDocument _resultXml;

        [BeforeScenario]
        public void cleanup()
        {
            try
            {
                Directory.Delete("Results", true);
            }
            catch (DirectoryNotFoundException)
            {
                //ignore
            }
            Directory.CreateDirectory("Results");
        }


        [Given(@"CC Report (.*) produced by (.*) tool")]
        public void SetCCReportAndTool(string ccFile, string toolName)
        {
            CrapAnalyzer.CCParser = CCParserFactory.CreateParser(toolName);
            _ccFileName = Path.Combine(_path, ccFile);

        }

        [Given(@"Coverage Report (.*)produced by (.*)")]
        public void SetCoverageReportAndTool(string covFile, string toolName)
        {
            CrapAnalyzer.CoverageParser = CoverageParserFactory.CreateParser(toolName);
            _covFileName = Path.Combine(_path, covFile);
        }

        [When("Creating crap Report (.*)")]
        void CreateReport(string resultFileName)
        {
            var Results = CrapAnalyzer.CreateCrapReport(_covFileName, _ccFileName);
            IFormatter formatter = new XmlFormatter();
            var dir = Path.GetDirectoryName(resultFileName);
            if (!Directory.Exists(dir))
                Directory.CreateDirectory(dir);
            formatter.FormatAndSaveToFile(Results, resultFileName);
        }

        [Then("(.*) Contains (.*) values")]
        public void VerifyResults(string fileName, string num)
        {
            _resultXml = XDocument.Load(fileName);
            var methods = from method in _resultXml.Descendants()
                          where method.Name.LocalName == "Method"
                          select method;
            try
            {
                Assert.AreEqual(Int16.Parse(num), methods.Count());
            }
            catch (Exception)
            {
                PrintResults(methods);
                throw;
            }
            finally
            {
                //File.Delete(fileName);
            }
        }

        [Then("^(.*) Contains The Following Values:")]
        public void VerifyResultContent(string fileName, Table table)
        {
            _resultXml = XDocument.Load(fileName);
            var MissingMethods = "";
            foreach (var row in table.Rows)
            {
                if (VerifyMethodIsInResult(row["DLL"],
                    row["NameSpace"],
                    row["ClassName"],
                    row["MethodName"],
                    row["Args"],
                    row["Crap"]) != true)
                {
                    MissingMethods += string.Format("{0}:{1}.{2}.{3}({4}) : {5}",
                        row["DLL"].Trim(),
                        row["NameSpace"].Trim(),
                        row["ClassName"].Trim(),
                        row["MethodName"].Trim(),
                        row["Args"].Trim(),
                        row["Crap"].Trim()) + Environment.NewLine;
                }
            }
            if (string.IsNullOrEmpty(MissingMethods) == false)
            {
                Assert.Fail("didnt find content in report: "+Environment.NewLine + MissingMethods + _resultXml);
            }

        }

        private bool VerifyMethodIsInResult(string DLL, string NameSpace,
            string ClassName,
            string MethodName,
            string Args,
            string Crap)
        {
            var methods = from method in _resultXml.Descendants()
                          where method.Name.LocalName == "Method"
                          select method;

            var found = new List<XElement>();
            foreach (var item in methods)
            {
                if (Matching(DLL, NameSpace, ClassName, MethodName, Args, Crap, item))
                    return true;
            }
            return false;
        }

        private static bool Matching(string DLL,
            string NameSpace,
            string ClassName,
            string MethodName,
            string Args,
            string Crap,
            XElement result)
        {
            if (result.Attribute("Assembly").Value != DLL.Trim())
                return false;
            if (result.Attribute("NameSpace").Value != NameSpace.Trim())
                return false;
            if (result.Attribute("Type").Value != ClassName.Trim())
                return false;
            if (result.Attribute("Name").Value != MethodName.Trim())
                return false;
            if (result.Attribute("Args").Value != Args.Trim())
                return false;
            if (result.Attribute("Crap").Value != Crap.Trim())
                return false;
            return true;
        }

        private void PrintResults(IEnumerable<XElement> methods)
        {
            foreach (var method in methods)
            {
                var msg = String.Format("{0},{1},{2}",
                    method.Attribute("Type").Value,
                    method.Attribute("Name").Value,
                    method.Attribute("Crap").Value
                    );

                Console.WriteLine(msg);
            }

        }
 
    }
}
